//
//
// bg_lib,c -- standard C library replacement routines used by code
// compiled for the virtual machine

#ifdef Q3_VM

#include "../qcommon/q_shared.h"

/*-
 * Copyright (c) 1992, 1993
 *	The Regents of the University of California.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#include "bg_lib.h"

#if defined(LIBC_SCCS) && !defined(lint)
#if 0
static char sccsid[] = "@(#)qsort.c	8.1 (Berkeley) 6/4/93";
#endif
static const char rcsid[] =
#endif /* LIBC_SCCS and not lint */

		static char* med3(char *, char *, char *, cmp_t *);
static void swapfunc(char *, char *, int, int);

#ifndef min
#define min(a, b) ((a) < (b) ? (a) : (b))
#endif

/*
 * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function".
 */
#define swapcode(TYPE, parmi, parmj, n) {   \
	long i = (n) / sizeof (TYPE);    \
	register TYPE *pi = (TYPE *) (parmi);   \
	register TYPE *pj = (TYPE *) (parmj);   \
	do {       \
		register TYPE t = *pi;  \
		*pi++ = *pj;    \
		*pj++ = t;    \
        } while (--i > 0);    \
}

#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \
	es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1;

static void
swapfunc(a, b, n, swaptype)
char *a, *b;
int n, swaptype;
{
	if (swaptype <= 1)
		swapcode(long, a, b, n)
	else
		swapcode(char, a, b, n)
	}

#define swap(a, b)     \
	if (swaptype == 0) {    \
		long t = *(long *)(a);   \
		*(long *)(a) = *(long *)(b);  \
		*(long *)(b) = t;   \
	} else      \
		swapfunc(a, b, es, swaptype)

#define vecswap(a, b, n)  if ((n) > 0) swapfunc(a, b, n, swaptype)

static char *
med3(a, b, c, cmp)
char *a, *b, *c;
cmp_t *cmp;
{
	return cmp(a, b) < 0 ?
			(cmp(b, c) < 0 ? b : (cmp(a, c) < 0 ? c : a))
			: (cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c));
}

void
qsort(a, n, es, cmp)
void *a;
size_t n, es;
cmp_t *cmp;
{
	char *pa, *pb, *pc, *pd, *pl, *pm, *pn;
	int d, r, swaptype, swap_cnt;

loop:
	SWAPINIT(a, es);
	swap_cnt = 0;
	if (n < 7) {
		for (pm = (char *) a + es; pm < (char *) a + n * es; pm += es)
			for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0;
					pl -= es)
				swap(pl, pl - es);
		return;
	}
	pm = (char *) a + (n / 2) * es;
	if (n > 7) {
		pl = a;
		pn = (char *) a + (n - 1) * es;
		if (n > 40) {
			d = (n / 8) * es;
			pl = med3(pl, pl + d, pl + 2 * d, cmp);
			pm = med3(pm - d, pm, pm + d, cmp);
			pn = med3(pn - 2 * d, pn - d, pn, cmp);
		}
		pm = med3(pl, pm, pn, cmp);
	}
	swap(a, pm);
	pa = pb = (char *) a + es;

	pc = pd = (char *) a + (n - 1) * es;
	for (;;) {
		while (pb <= pc && (r = cmp(pb, a)) <= 0) {
			if (r == 0) {
				swap_cnt = 1;
				swap(pa, pb);
				pa += es;
			}
			pb += es;
		}
		while (pb <= pc && (r = cmp(pc, a)) >= 0) {
			if (r == 0) {
				swap_cnt = 1;
				swap(pc, pd);
				pd -= es;
			}
			pc -= es;
		}
		if (pb > pc)
			break;
		swap(pb, pc);
		swap_cnt = 1;
		pb += es;
		pc -= es;
	}
	if (swap_cnt == 0) { /* Switch to insertion sort */
		for (pm = (char *) a + es; pm < (char *) a + n * es; pm += es)
			for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0;
					pl -= es)
				swap(pl, pl - es);
		return;
	}

	pn = (char *) a + n * es;
	r = min(pa - (char *) a, pb - pa);
	vecswap(a, pb - r, r);
	r = min(pd - pc, pn - pd - es);
	vecswap(pb, pn - r, r);
	if ((r = pb - pa) > es)
		qsort(a, r / es, es, cmp);
	if ((r = pd - pc) > es) {
		/* Iterate rather than recurse to save stack space */
		a = pn - r;
		n = r / es;
		goto loop;
	}
	/*		qsort(pn - r, r / es, es, cmp);*/
}

//==================================================================================

size_t strlen(const char *string) {
	const char *s;

	s = string;
	while (*s) {
		s++;
	}
	return s - string;
}

char *strcat(char *strDestination, const char *strSource) {
	char *s;

	s = strDestination;
	while (*s) {
		s++;
	}
	while (*strSource) {
		*s++ = *strSource++;
	}
	*s = 0;
	return strDestination;
}

char *strcpy(char *strDestination, const char *strSource) {
	char *s;

	s = strDestination;
	while (*strSource) {
		*s++ = *strSource++;
	}
	*s = 0;
	return strDestination;
}

int strcmp(const char *string1, const char *string2) {
	while (*string1 == *string2 && *string1 && *string2) {
		string1++;
		string2++;
	}
	return *string1 - *string2;
}

char *strchr(const char *string, int c) {
	while (*string) {
		if (*string == c) {
			return (char *) string;
		}
		string++;
	}
	if (c)
		return NULL;
	else
		return (char*) string;
}

char *strrchr(const char *string, int c) {
	const char *found = NULL;

	while (*string) {
		if (*string == c)
			found = string;

		string++;
	}

	if (c)
		return (char *) found;
	else
		return (char *) string;
}

char *strstr(const char *string, const char *strCharSet) {
	while (*string) {
		int i;

		for (i = 0; strCharSet[i]; i++) {
			if (string[i] != strCharSet[i]) {
				break;
			}
		}
		if (!strCharSet[i]) {
			return (char *) string;
		}
		string++;
	}
	return (char *) 0;
}

int tolower(int c) {
	if (c >= 'A' && c <= 'Z') {
		c += 'a' - 'A';
	}
	return c;
}

int toupper(int c) {
	if (c >= 'a' && c <= 'z') {
		c += 'A' - 'a';
	}
	return c;
}

void *memmove(void *dest, const void *src, size_t count) {
	int i;

	if (dest > src) {
		for (i = count - 1; i >= 0; i--) {
			((char *) dest)[i] = ((char *) src)[i];
		}
	} else {
		for (i = 0; i < count; i++) {
			((char *) dest)[i] = ((char *) src)[i];
		}
	}
	return dest;
}


#if 0

double floor(double x) {
	return (int) (x + 0x40000000) - 0x40000000;
}

void *memset(void *dest, int c, size_t count) {
	while (count--) {
		((char *) dest)[count] = c;
	}
	return dest;
}

void *memcpy(void *dest, const void *src, size_t count) {
	while (count--) {
		((char *) dest)[count] = ((char *) src)[count];
	}
	return dest;
}

char *strncpy(char *strDest, const char *strSource, size_t count) {
	char *s;

	s = strDest;
	while (*strSource && count) {
		*s++ = *strSource++;
		count--;
	}
	while (count--) {
		*s++ = 0;
	}
	return strDest;
}

double sqrt(double x) {
	float y;
	float delta;
	float maxError;

	if (x <= 0) {
		return 0;
	}

	// initial guess
	y = x / 2;

	// refine
	maxError = x * 0.001;

	do {
		delta = (y * y) - x;
		y -= delta / (2 * y);
	} while (delta > maxError || delta < -maxError);

	return y;
}


float sintable[1024] = {
	0.000000, 0.001534, 0.003068, 0.004602, 0.006136, 0.007670, 0.009204, 0.010738,
	0.012272, 0.013805, 0.015339, 0.016873, 0.018407, 0.019940, 0.021474, 0.023008,
	0.024541, 0.026075, 0.027608, 0.029142, 0.030675, 0.032208, 0.033741, 0.035274,
	0.036807, 0.038340, 0.039873, 0.041406, 0.042938, 0.044471, 0.046003, 0.047535,
	0.049068, 0.050600, 0.052132, 0.053664, 0.055195, 0.056727, 0.058258, 0.059790,
	0.061321, 0.062852, 0.064383, 0.065913, 0.067444, 0.068974, 0.070505, 0.072035,
	0.073565, 0.075094, 0.076624, 0.078153, 0.079682, 0.081211, 0.082740, 0.084269,
	0.085797, 0.087326, 0.088854, 0.090381, 0.091909, 0.093436, 0.094963, 0.096490,
	0.098017, 0.099544, 0.101070, 0.102596, 0.104122, 0.105647, 0.107172, 0.108697,
	0.110222, 0.111747, 0.113271, 0.114795, 0.116319, 0.117842, 0.119365, 0.120888,
	0.122411, 0.123933, 0.125455, 0.126977, 0.128498, 0.130019, 0.131540, 0.133061,
	0.134581, 0.136101, 0.137620, 0.139139, 0.140658, 0.142177, 0.143695, 0.145213,
	0.146730, 0.148248, 0.149765, 0.151281, 0.152797, 0.154313, 0.155828, 0.157343,
	0.158858, 0.160372, 0.161886, 0.163400, 0.164913, 0.166426, 0.167938, 0.169450,
	0.170962, 0.172473, 0.173984, 0.175494, 0.177004, 0.178514, 0.180023, 0.181532,
	0.183040, 0.184548, 0.186055, 0.187562, 0.189069, 0.190575, 0.192080, 0.193586,
	0.195090, 0.196595, 0.198098, 0.199602, 0.201105, 0.202607, 0.204109, 0.205610,
	0.207111, 0.208612, 0.210112, 0.211611, 0.213110, 0.214609, 0.216107, 0.217604,
	0.219101, 0.220598, 0.222094, 0.223589, 0.225084, 0.226578, 0.228072, 0.229565,
	0.231058, 0.232550, 0.234042, 0.235533, 0.237024, 0.238514, 0.240003, 0.241492,
	0.242980, 0.244468, 0.245955, 0.247442, 0.248928, 0.250413, 0.251898, 0.253382,
	0.254866, 0.256349, 0.257831, 0.259313, 0.260794, 0.262275, 0.263755, 0.265234,
	0.266713, 0.268191, 0.269668, 0.271145, 0.272621, 0.274097, 0.275572, 0.277046,
	0.278520, 0.279993, 0.281465, 0.282937, 0.284408, 0.285878, 0.287347, 0.288816,
	0.290285, 0.291752, 0.293219, 0.294685, 0.296151, 0.297616, 0.299080, 0.300543,
	0.302006, 0.303468, 0.304929, 0.306390, 0.307850, 0.309309, 0.310767, 0.312225,
	0.313682, 0.315138, 0.316593, 0.318048, 0.319502, 0.320955, 0.322408, 0.323859,
	0.325310, 0.326760, 0.328210, 0.329658, 0.331106, 0.332553, 0.334000, 0.335445,
	0.336890, 0.338334, 0.339777, 0.341219, 0.342661, 0.344101, 0.345541, 0.346980,
	0.348419, 0.349856, 0.351293, 0.352729, 0.354164, 0.355598, 0.357031, 0.358463,
	0.359895, 0.361326, 0.362756, 0.364185, 0.365613, 0.367040, 0.368467, 0.369892,
	0.371317, 0.372741, 0.374164, 0.375586, 0.377007, 0.378428, 0.379847, 0.381266,
	0.382683, 0.384100, 0.385516, 0.386931, 0.388345, 0.389758, 0.391170, 0.392582,
	0.393992, 0.395401, 0.396810, 0.398218, 0.399624, 0.401030, 0.402435, 0.403838,
	0.405241, 0.406643, 0.408044, 0.409444, 0.410843, 0.412241, 0.413638, 0.415034,
	0.416430, 0.417824, 0.419217, 0.420609, 0.422000, 0.423390, 0.424780, 0.426168,
	0.427555, 0.428941, 0.430326, 0.431711, 0.433094, 0.434476, 0.435857, 0.437237,
	0.438616, 0.439994, 0.441371, 0.442747, 0.444122, 0.445496, 0.446869, 0.448241,
	0.449611, 0.450981, 0.452350, 0.453717, 0.455084, 0.456449, 0.457813, 0.459177,
	0.460539, 0.461900, 0.463260, 0.464619, 0.465976, 0.467333, 0.468689, 0.470043,
	0.471397, 0.472749, 0.474100, 0.475450, 0.476799, 0.478147, 0.479494, 0.480839,
	0.482184, 0.483527, 0.484869, 0.486210, 0.487550, 0.488889, 0.490226, 0.491563,
	0.492898, 0.494232, 0.495565, 0.496897, 0.498228, 0.499557, 0.500885, 0.502212,
	0.503538, 0.504863, 0.506187, 0.507509, 0.508830, 0.510150, 0.511469, 0.512786,
	0.514103, 0.515418, 0.516732, 0.518045, 0.519356, 0.520666, 0.521975, 0.523283,
	0.524590, 0.525895, 0.527199, 0.528502, 0.529804, 0.531104, 0.532403, 0.533701,
	0.534998, 0.536293, 0.537587, 0.538880, 0.540171, 0.541462, 0.542751, 0.544039,
	0.545325, 0.546610, 0.547894, 0.549177, 0.550458, 0.551738, 0.553017, 0.554294,
	0.555570, 0.556845, 0.558119, 0.559391, 0.560662, 0.561931, 0.563199, 0.564466,
	0.565732, 0.566996, 0.568259, 0.569521, 0.570781, 0.572040, 0.573297, 0.574553,
	0.575808, 0.577062, 0.578314, 0.579565, 0.580814, 0.582062, 0.583309, 0.584554,
	0.585798, 0.587040, 0.588282, 0.589521, 0.590760, 0.591997, 0.593232, 0.594466,
	0.595699, 0.596931, 0.598161, 0.599389, 0.600616, 0.601842, 0.603067, 0.604290,
	0.605511, 0.606731, 0.607950, 0.609167, 0.610383, 0.611597, 0.612810, 0.614022,
	0.615232, 0.616440, 0.617647, 0.618853, 0.620057, 0.621260, 0.622461, 0.623661,
	0.624859, 0.626056, 0.627252, 0.628446, 0.629638, 0.630829, 0.632019, 0.633207,
	0.634393, 0.635578, 0.636762, 0.637944, 0.639124, 0.640303, 0.641481, 0.642657,
	0.643832, 0.645005, 0.646176, 0.647346, 0.648514, 0.649681, 0.650847, 0.652011,
	0.653173, 0.654334, 0.655493, 0.656651, 0.657807, 0.658961, 0.660114, 0.661266,
	0.662416, 0.663564, 0.664711, 0.665856, 0.667000, 0.668142, 0.669283, 0.670422,
	0.671559, 0.672695, 0.673829, 0.674962, 0.676093, 0.677222, 0.678350, 0.679476,
	0.680601, 0.681724, 0.682846, 0.683965, 0.685084, 0.686200, 0.687315, 0.688429,
	0.689541, 0.690651, 0.691759, 0.692866, 0.693971, 0.695075, 0.696177, 0.697278,
	0.698376, 0.699473, 0.700569, 0.701663, 0.702755, 0.703845, 0.704934, 0.706021,
	0.707107, 0.708191, 0.709273, 0.710353, 0.711432, 0.712509, 0.713585, 0.714659,
	0.715731, 0.716801, 0.717870, 0.718937, 0.720003, 0.721066, 0.722128, 0.723188,
	0.724247, 0.725304, 0.726359, 0.727413, 0.728464, 0.729514, 0.730563, 0.731609,
	0.732654, 0.733697, 0.734739, 0.735779, 0.736817, 0.737853, 0.738887, 0.739920,
	0.740951, 0.741980, 0.743008, 0.744034, 0.745058, 0.746080, 0.747101, 0.748119,
	0.749136, 0.750152, 0.751165, 0.752177, 0.753187, 0.754195, 0.755201, 0.756206,
	0.757209, 0.758210, 0.759209, 0.760207, 0.761202, 0.762196, 0.763188, 0.764179,
	0.765167, 0.766154, 0.767139, 0.768122, 0.769103, 0.770083, 0.771061, 0.772036,
	0.773010, 0.773983, 0.774953, 0.775922, 0.776888, 0.777853, 0.778817, 0.779778,
	0.780737, 0.781695, 0.782651, 0.783605, 0.784557, 0.785507, 0.786455, 0.787402,
	0.788346, 0.789289, 0.790230, 0.791169, 0.792107, 0.793042, 0.793975, 0.794907,
	0.795837, 0.796765, 0.797691, 0.798615, 0.799537, 0.800458, 0.801376, 0.802293,
	0.803208, 0.804120, 0.805031, 0.805940, 0.806848, 0.807753, 0.808656, 0.809558,
	0.810457, 0.811355, 0.812251, 0.813144, 0.814036, 0.814926, 0.815814, 0.816701,
	0.817585, 0.818467, 0.819348, 0.820226, 0.821103, 0.821977, 0.822850, 0.823721,
	0.824589, 0.825456, 0.826321, 0.827184, 0.828045, 0.828904, 0.829761, 0.830616,
	0.831470, 0.832321, 0.833170, 0.834018, 0.834863, 0.835706, 0.836548, 0.837387,
	0.838225, 0.839060, 0.839894, 0.840725, 0.841555, 0.842383, 0.843208, 0.844032,
	0.844854, 0.845673, 0.846491, 0.847307, 0.848120, 0.848932, 0.849742, 0.850549,
	0.851355, 0.852159, 0.852961, 0.853760, 0.854558, 0.855354, 0.856147, 0.856939,
	0.857729, 0.858516, 0.859302, 0.860085, 0.860867, 0.861646, 0.862424, 0.863199,
	0.863973, 0.864744, 0.865514, 0.866281, 0.867046, 0.867809, 0.868571, 0.869330,
	0.870087, 0.870842, 0.871595, 0.872346, 0.873095, 0.873842, 0.874587, 0.875329,
	0.876070, 0.876809, 0.877545, 0.878280, 0.879012, 0.879743, 0.880471, 0.881197,
	0.881921, 0.882643, 0.883363, 0.884081, 0.884797, 0.885511, 0.886223, 0.886932,
	0.887640, 0.888345, 0.889048, 0.889750, 0.890449, 0.891146, 0.891841, 0.892534,
	0.893224, 0.893913, 0.894599, 0.895284, 0.895966, 0.896646, 0.897325, 0.898001,
	0.898674, 0.899346, 0.900016, 0.900683, 0.901349, 0.902012, 0.902673, 0.903332,
	0.903989, 0.904644, 0.905297, 0.905947, 0.906596, 0.907242, 0.907886, 0.908528,
	0.909168, 0.909806, 0.910441, 0.911075, 0.911706, 0.912335, 0.912962, 0.913587,
	0.914210, 0.914830, 0.915449, 0.916065, 0.916679, 0.917291, 0.917901, 0.918508,
	0.919114, 0.919717, 0.920318, 0.920917, 0.921514, 0.922109, 0.922701, 0.923291,
	0.923880, 0.924465, 0.925049, 0.925631, 0.926210, 0.926787, 0.927363, 0.927935,
	0.928506, 0.929075, 0.929641, 0.930205, 0.930767, 0.931327, 0.931884, 0.932440,
	0.932993, 0.933544, 0.934093, 0.934639, 0.935184, 0.935726, 0.936266, 0.936803,
	0.937339, 0.937872, 0.938404, 0.938932, 0.939459, 0.939984, 0.940506, 0.941026,
	0.941544, 0.942060, 0.942573, 0.943084, 0.943593, 0.944100, 0.944605, 0.945107,
	0.945607, 0.946105, 0.946601, 0.947094, 0.947586, 0.948075, 0.948561, 0.949046,
	0.949528, 0.950008, 0.950486, 0.950962, 0.951435, 0.951906, 0.952375, 0.952842,
	0.953306, 0.953768, 0.954228, 0.954686, 0.955141, 0.955594, 0.956045, 0.956494,
	0.956940, 0.957385, 0.957826, 0.958266, 0.958703, 0.959139, 0.959572, 0.960002,
	0.960431, 0.960857, 0.961280, 0.961702, 0.962121, 0.962538, 0.962953, 0.963366,
	0.963776, 0.964184, 0.964590, 0.964993, 0.965394, 0.965793, 0.966190, 0.966584,
	0.966976, 0.967366, 0.967754, 0.968139, 0.968522, 0.968903, 0.969281, 0.969657,
	0.970031, 0.970403, 0.970772, 0.971139, 0.971504, 0.971866, 0.972226, 0.972584,
	0.972940, 0.973293, 0.973644, 0.973993, 0.974339, 0.974684, 0.975025, 0.975365,
	0.975702, 0.976037, 0.976370, 0.976700, 0.977028, 0.977354, 0.977677, 0.977999,
	0.978317, 0.978634, 0.978948, 0.979260, 0.979570, 0.979877, 0.980182, 0.980485,
	0.980785, 0.981083, 0.981379, 0.981673, 0.981964, 0.982253, 0.982539, 0.982824,
	0.983105, 0.983385, 0.983662, 0.983937, 0.984210, 0.984480, 0.984749, 0.985014,
	0.985278, 0.985539, 0.985798, 0.986054, 0.986308, 0.986560, 0.986809, 0.987057,
	0.987301, 0.987544, 0.987784, 0.988022, 0.988258, 0.988491, 0.988722, 0.988950,
	0.989177, 0.989400, 0.989622, 0.989841, 0.990058, 0.990273, 0.990485, 0.990695,
	0.990903, 0.991108, 0.991311, 0.991511, 0.991710, 0.991906, 0.992099, 0.992291,
	0.992480, 0.992666, 0.992850, 0.993032, 0.993212, 0.993389, 0.993564, 0.993737,
	0.993907, 0.994075, 0.994240, 0.994404, 0.994565, 0.994723, 0.994879, 0.995033,
	0.995185, 0.995334, 0.995481, 0.995625, 0.995767, 0.995907, 0.996045, 0.996180,
	0.996313, 0.996443, 0.996571, 0.996697, 0.996820, 0.996941, 0.997060, 0.997176,
	0.997290, 0.997402, 0.997511, 0.997618, 0.997723, 0.997825, 0.997925, 0.998023,
	0.998118, 0.998211, 0.998302, 0.998390, 0.998476, 0.998559, 0.998640, 0.998719,
	0.998795, 0.998870, 0.998941, 0.999011, 0.999078, 0.999142, 0.999205, 0.999265,
	0.999322, 0.999378, 0.999431, 0.999481, 0.999529, 0.999575, 0.999619, 0.999660,
	0.999699, 0.999735, 0.999769, 0.999801, 0.999831, 0.999858, 0.999882, 0.999905,
	0.999925, 0.999942, 0.999958, 0.999971, 0.999981, 0.999989, 0.999995, 0.999999
};

double sin(double x) {
	int index;
	int quad;

	index = 1024 * x / (M_PI * 0.5);
	quad = (index >> 10) & 3;
	index &= 1023;
	switch (quad) {
		case 0:
			return sintable[index];
		case 1:
			return sintable[1023 - index];
		case 2:
			return -sintable[index];
		case 3:
			return -sintable[1023 - index];
	}
	return 0;
}

double cos(double x) {
	int index;
	int quad;

	index = 1024 * x / (M_PI * 0.5);
	quad = (index >> 10) & 3;
	index &= 1023;
	switch (quad) {
		case 3:
			return sintable[index];
		case 0:
			return sintable[1023 - index];
		case 1:
			return -sintable[index];
		case 2:
			return -sintable[1023 - index];
	}
	return 0;
}


/*
void create_acostable( void ) {
	int i;
	FILE *fp;
	float a;

	fp = fopen("c:\\acostable.txt", "w");
	fprintf(fp, "float acostable[] = {");
	for (i = 0; i < 1024; i++) {
		if (!(i & 7))
			fprintf(fp, "\n");
		a = acos( (float) -1 + i / 512 );
		fprintf(fp, "%1.8f,", a);
	}
	fprintf(fp, "\n}\n");
	fclose(fp);
}
 */

float acostable[] = {
	3.14159265, 3.07908248, 3.05317551, 3.03328655, 3.01651113, 3.00172442, 2.98834964, 2.97604422,
	2.96458497, 2.95381690, 2.94362719, 2.93393068, 2.92466119, 2.91576615, 2.90720289, 2.89893629,
	2.89093699, 2.88318015, 2.87564455, 2.86831188, 2.86116621, 2.85419358, 2.84738169, 2.84071962,
	2.83419760, 2.82780691, 2.82153967, 2.81538876, 2.80934770, 2.80341062, 2.79757211, 2.79182724,
	2.78617145, 2.78060056, 2.77511069, 2.76969824, 2.76435988, 2.75909250, 2.75389319, 2.74875926,
	2.74368816, 2.73867752, 2.73372510, 2.72882880, 2.72398665, 2.71919677, 2.71445741, 2.70976688,
	2.70512362, 2.70052613, 2.69597298, 2.69146283, 2.68699438, 2.68256642, 2.67817778, 2.67382735,
	2.66951407, 2.66523692, 2.66099493, 2.65678719, 2.65261279, 2.64847088, 2.64436066, 2.64028133,
	2.63623214, 2.63221238, 2.62822133, 2.62425835, 2.62032277, 2.61641398, 2.61253138, 2.60867440,
	2.60484248, 2.60103507, 2.59725167, 2.59349176, 2.58975488, 2.58604053, 2.58234828, 2.57867769,
	2.57502832, 2.57139977, 2.56779164, 2.56420354, 2.56063509, 2.55708594, 2.55355572, 2.55004409,
	2.54655073, 2.54307530, 2.53961750, 2.53617701, 2.53275354, 2.52934680, 2.52595650, 2.52258238,
	2.51922417, 2.51588159, 2.51255441, 2.50924238, 2.50594525, 2.50266278, 2.49939476, 2.49614096,
	2.49290115, 2.48967513, 2.48646269, 2.48326362, 2.48007773, 2.47690482, 2.47374472, 2.47059722,
	2.46746215, 2.46433933, 2.46122860, 2.45812977, 2.45504269, 2.45196720, 2.44890314, 2.44585034,
	2.44280867, 2.43977797, 2.43675809, 2.43374890, 2.43075025, 2.42776201, 2.42478404, 2.42181622,
	2.41885841, 2.41591048, 2.41297232, 2.41004380, 2.40712480, 2.40421521, 2.40131491, 2.39842379,
	2.39554173, 2.39266863, 2.38980439, 2.38694889, 2.38410204, 2.38126374, 2.37843388, 2.37561237,
	2.37279910, 2.36999400, 2.36719697, 2.36440790, 2.36162673, 2.35885335, 2.35608768, 2.35332964,
	2.35057914, 2.34783610, 2.34510044, 2.34237208, 2.33965094, 2.33693695, 2.33423003, 2.33153010,
	2.32883709, 2.32615093, 2.32347155, 2.32079888, 2.31813284, 2.31547337, 2.31282041, 2.31017388,
	2.30753373, 2.30489988, 2.30227228, 2.29965086, 2.29703556, 2.29442632, 2.29182309, 2.28922580,
	2.28663439, 2.28404881, 2.28146900, 2.27889490, 2.27632647, 2.27376364, 2.27120637, 2.26865460,
	2.26610827, 2.26356735, 2.26103177, 2.25850149, 2.25597646, 2.25345663, 2.25094195, 2.24843238,
	2.24592786, 2.24342836, 2.24093382, 2.23844420, 2.23595946, 2.23347956, 2.23100444, 2.22853408,
	2.22606842, 2.22360742, 2.22115104, 2.21869925, 2.21625199, 2.21380924, 2.21137096, 2.20893709,
	2.20650761, 2.20408248, 2.20166166, 2.19924511, 2.19683280, 2.19442469, 2.19202074, 2.18962092,
	2.18722520, 2.18483354, 2.18244590, 2.18006225, 2.17768257, 2.17530680, 2.17293493, 2.17056692,
	2.16820274, 2.16584236, 2.16348574, 2.16113285, 2.15878367, 2.15643816, 2.15409630, 2.15175805,
	2.14942338, 2.14709226, 2.14476468, 2.14244059, 2.14011997, 2.13780279, 2.13548903, 2.13317865,
	2.13087163, 2.12856795, 2.12626757, 2.12397047, 2.12167662, 2.11938600, 2.11709859, 2.11481435,
	2.11253326, 2.11025530, 2.10798044, 2.10570867, 2.10343994, 2.10117424, 2.09891156, 2.09665185,
	2.09439510, 2.09214129, 2.08989040, 2.08764239, 2.08539725, 2.08315496, 2.08091550, 2.07867884,
	2.07644495, 2.07421383, 2.07198545, 2.06975978, 2.06753681, 2.06531651, 2.06309887, 2.06088387,
	2.05867147, 2.05646168, 2.05425445, 2.05204979, 2.04984765, 2.04764804, 2.04545092, 2.04325628,
	2.04106409, 2.03887435, 2.03668703, 2.03450211, 2.03231957, 2.03013941, 2.02796159, 2.02578610,
	2.02361292, 2.02144204, 2.01927344, 2.01710710, 2.01494300, 2.01278113, 2.01062146, 2.00846399,
	2.00630870, 2.00415556, 2.00200457, 1.99985570, 1.99770895, 1.99556429, 1.99342171, 1.99128119,
	1.98914271, 1.98700627, 1.98487185, 1.98273942, 1.98060898, 1.97848051, 1.97635399, 1.97422942,
	1.97210676, 1.96998602, 1.96786718, 1.96575021, 1.96363511, 1.96152187, 1.95941046, 1.95730088,
	1.95519310, 1.95308712, 1.95098292, 1.94888050, 1.94677982, 1.94468089, 1.94258368, 1.94048818,
	1.93839439, 1.93630228, 1.93421185, 1.93212308, 1.93003595, 1.92795046, 1.92586659, 1.92378433,
	1.92170367, 1.91962459, 1.91754708, 1.91547113, 1.91339673, 1.91132385, 1.90925250, 1.90718266,
	1.90511432, 1.90304746, 1.90098208, 1.89891815, 1.89685568, 1.89479464, 1.89273503, 1.89067683,
	1.88862003, 1.88656463, 1.88451060, 1.88245794, 1.88040664, 1.87835668, 1.87630806, 1.87426076,
	1.87221477, 1.87017008, 1.86812668, 1.86608457, 1.86404371, 1.86200412, 1.85996577, 1.85792866,
	1.85589277, 1.85385809, 1.85182462, 1.84979234, 1.84776125, 1.84573132, 1.84370256, 1.84167495,
	1.83964848, 1.83762314, 1.83559892, 1.83357582, 1.83155381, 1.82953289, 1.82751305, 1.82549429,
	1.82347658, 1.82145993, 1.81944431, 1.81742973, 1.81541617, 1.81340362, 1.81139207, 1.80938151,
	1.80737194, 1.80536334, 1.80335570, 1.80134902, 1.79934328, 1.79733848, 1.79533460, 1.79333164,
	1.79132959, 1.78932843, 1.78732817, 1.78532878, 1.78333027, 1.78133261, 1.77933581, 1.77733985,
	1.77534473, 1.77335043, 1.77135695, 1.76936428, 1.76737240, 1.76538132, 1.76339101, 1.76140148,
	1.75941271, 1.75742470, 1.75543743, 1.75345090, 1.75146510, 1.74948002, 1.74749565, 1.74551198,
	1.74352900, 1.74154672, 1.73956511, 1.73758417, 1.73560389, 1.73362426, 1.73164527, 1.72966692,
	1.72768920, 1.72571209, 1.72373560, 1.72175971, 1.71978441, 1.71780969, 1.71583556, 1.71386199,
	1.71188899, 1.70991653, 1.70794462, 1.70597325, 1.70400241, 1.70203209, 1.70006228, 1.69809297,
	1.69612416, 1.69415584, 1.69218799, 1.69022062, 1.68825372, 1.68628727, 1.68432127, 1.68235571,
	1.68039058, 1.67842588, 1.67646160, 1.67449772, 1.67253424, 1.67057116, 1.66860847, 1.66664615,
	1.66468420, 1.66272262, 1.66076139, 1.65880050, 1.65683996, 1.65487975, 1.65291986, 1.65096028,
	1.64900102, 1.64704205, 1.64508338, 1.64312500, 1.64116689, 1.63920905, 1.63725148, 1.63529416,
	1.63333709, 1.63138026, 1.62942366, 1.62746728, 1.62551112, 1.62355517, 1.62159943, 1.61964388,
	1.61768851, 1.61573332, 1.61377831, 1.61182346, 1.60986877, 1.60791422, 1.60595982, 1.60400556,
	1.60205142, 1.60009739, 1.59814349, 1.59618968, 1.59423597, 1.59228235, 1.59032882, 1.58837536,
	1.58642196, 1.58446863, 1.58251535, 1.58056211, 1.57860891, 1.57665574, 1.57470259, 1.57274945,
	1.57079633, 1.56884320, 1.56689007, 1.56493692, 1.56298375, 1.56103055, 1.55907731, 1.55712403,
	1.55517069, 1.55321730, 1.55126383, 1.54931030, 1.54735668, 1.54540297, 1.54344917, 1.54149526,
	1.53954124, 1.53758710, 1.53563283, 1.53367843, 1.53172389, 1.52976919, 1.52781434, 1.52585933,
	1.52390414, 1.52194878, 1.51999323, 1.51803748, 1.51608153, 1.51412537, 1.51216900, 1.51021240,
	1.50825556, 1.50629849, 1.50434117, 1.50238360, 1.50042576, 1.49846765, 1.49650927, 1.49455060,
	1.49259163, 1.49063237, 1.48867280, 1.48671291, 1.48475270, 1.48279215, 1.48083127, 1.47887004,
	1.47690845, 1.47494650, 1.47298419, 1.47102149, 1.46905841, 1.46709493, 1.46513106, 1.46316677,
	1.46120207, 1.45923694, 1.45727138, 1.45530538, 1.45333893, 1.45137203, 1.44940466, 1.44743682,
	1.44546850, 1.44349969, 1.44153038, 1.43956057, 1.43759024, 1.43561940, 1.43364803, 1.43167612,
	1.42970367, 1.42773066, 1.42575709, 1.42378296, 1.42180825, 1.41983295, 1.41785705, 1.41588056,
	1.41390346, 1.41192573, 1.40994738, 1.40796840, 1.40598877, 1.40400849, 1.40202755, 1.40004594,
	1.39806365, 1.39608068, 1.39409701, 1.39211264, 1.39012756, 1.38814175, 1.38615522, 1.38416795,
	1.38217994, 1.38019117, 1.37820164, 1.37621134, 1.37422025, 1.37222837, 1.37023570, 1.36824222,
	1.36624792, 1.36425280, 1.36225684, 1.36026004, 1.35826239, 1.35626387, 1.35426449, 1.35226422,
	1.35026307, 1.34826101, 1.34625805, 1.34425418, 1.34224937, 1.34024364, 1.33823695, 1.33622932,
	1.33422072, 1.33221114, 1.33020059, 1.32818904, 1.32617649, 1.32416292, 1.32214834, 1.32013273,
	1.31811607, 1.31609837, 1.31407960, 1.31205976, 1.31003885, 1.30801684, 1.30599373, 1.30396951,
	1.30194417, 1.29991770, 1.29789009, 1.29586133, 1.29383141, 1.29180031, 1.28976803, 1.28773456,
	1.28569989, 1.28366400, 1.28162688, 1.27958854, 1.27754894, 1.27550809, 1.27346597, 1.27142257,
	1.26937788, 1.26733189, 1.26528459, 1.26323597, 1.26118602, 1.25913471, 1.25708205, 1.25502803,
	1.25297262, 1.25091583, 1.24885763, 1.24679802, 1.24473698, 1.24267450, 1.24061058, 1.23854519,
	1.23647833, 1.23440999, 1.23234015, 1.23026880, 1.22819593, 1.22612152, 1.22404557, 1.22196806,
	1.21988898, 1.21780832, 1.21572606, 1.21364219, 1.21155670, 1.20946958, 1.20738080, 1.20529037,
	1.20319826, 1.20110447, 1.19900898, 1.19691177, 1.19481283, 1.19271216, 1.19060973, 1.18850553,
	1.18639955, 1.18429178, 1.18218219, 1.18007079, 1.17795754, 1.17584244, 1.17372548, 1.17160663,
	1.16948589, 1.16736324, 1.16523866, 1.16311215, 1.16098368, 1.15885323, 1.15672081, 1.15458638,
	1.15244994, 1.15031147, 1.14817095, 1.14602836, 1.14388370, 1.14173695, 1.13958808, 1.13743709,
	1.13528396, 1.13312866, 1.13097119, 1.12881153, 1.12664966, 1.12448556, 1.12231921, 1.12015061,
	1.11797973, 1.11580656, 1.11363107, 1.11145325, 1.10927308, 1.10709055, 1.10490563, 1.10271831,
	1.10052856, 1.09833638, 1.09614174, 1.09394462, 1.09174500, 1.08954287, 1.08733820, 1.08513098,
	1.08292118, 1.08070879, 1.07849378, 1.07627614, 1.07405585, 1.07183287, 1.06960721, 1.06737882,
	1.06514770, 1.06291382, 1.06067715, 1.05843769, 1.05619540, 1.05395026, 1.05170226, 1.04945136,
	1.04719755, 1.04494080, 1.04268110, 1.04041841, 1.03815271, 1.03588399, 1.03361221, 1.03133735,
	1.02905939, 1.02677830, 1.02449407, 1.02220665, 1.01991603, 1.01762219, 1.01532509, 1.01302471,
	1.01072102, 1.00841400, 1.00610363, 1.00378986, 1.00147268, 0.99915206, 0.99682798, 0.99450039,
	0.99216928, 0.98983461, 0.98749636, 0.98515449, 0.98280898, 0.98045980, 0.97810691, 0.97575030,
	0.97338991, 0.97102573, 0.96865772, 0.96628585, 0.96391009, 0.96153040, 0.95914675, 0.95675912,
	0.95436745, 0.95197173, 0.94957191, 0.94716796, 0.94475985, 0.94234754, 0.93993099, 0.93751017,
	0.93508504, 0.93265556, 0.93022170, 0.92778341, 0.92534066, 0.92289341, 0.92044161, 0.91798524,
	0.91552424, 0.91305858, 0.91058821, 0.90811309, 0.90563319, 0.90314845, 0.90065884, 0.89816430,
	0.89566479, 0.89316028, 0.89065070, 0.88813602, 0.88561619, 0.88309116, 0.88056088, 0.87802531,
	0.87548438, 0.87293806, 0.87038629, 0.86782901, 0.86526619, 0.86269775, 0.86012366, 0.85754385,
	0.85495827, 0.85236686, 0.84976956, 0.84716633, 0.84455709, 0.84194179, 0.83932037, 0.83669277,
	0.83405893, 0.83141877, 0.82877225, 0.82611928, 0.82345981, 0.82079378, 0.81812110, 0.81544172,
	0.81275556, 0.81006255, 0.80736262, 0.80465570, 0.80194171, 0.79922057, 0.79649221, 0.79375655,
	0.79101352, 0.78826302, 0.78550497, 0.78273931, 0.77996593, 0.77718475, 0.77439569, 0.77159865,
	0.76879355, 0.76598029, 0.76315878, 0.76032891, 0.75749061, 0.75464376, 0.75178826, 0.74892402,
	0.74605092, 0.74316887, 0.74027775, 0.73737744, 0.73446785, 0.73154885, 0.72862033, 0.72568217,
	0.72273425, 0.71977644, 0.71680861, 0.71383064, 0.71084240, 0.70784376, 0.70483456, 0.70181469,
	0.69878398, 0.69574231, 0.69268952, 0.68962545, 0.68654996, 0.68346288, 0.68036406, 0.67725332,
	0.67413051, 0.67099544, 0.66784794, 0.66468783, 0.66151492, 0.65832903, 0.65512997, 0.65191753,
	0.64869151, 0.64545170, 0.64219789, 0.63892987, 0.63564741, 0.63235028, 0.62903824, 0.62571106,
	0.62236849, 0.61901027, 0.61563615, 0.61224585, 0.60883911, 0.60541564, 0.60197515, 0.59851735,
	0.59504192, 0.59154856, 0.58803694, 0.58450672, 0.58095756, 0.57738911, 0.57380101, 0.57019288,
	0.56656433, 0.56291496, 0.55924437, 0.55555212, 0.55183778, 0.54810089, 0.54434099, 0.54055758,
	0.53675018, 0.53291825, 0.52906127, 0.52517867, 0.52126988, 0.51733431, 0.51337132, 0.50938028,
	0.50536051, 0.50131132, 0.49723200, 0.49312177, 0.48897987, 0.48480547, 0.48059772, 0.47635573,
	0.47207859, 0.46776530, 0.46341487, 0.45902623, 0.45459827, 0.45012983, 0.44561967, 0.44106652,
	0.43646903, 0.43182577, 0.42713525, 0.42239588, 0.41760600, 0.41276385, 0.40786755, 0.40291513,
	0.39790449, 0.39283339, 0.38769946, 0.38250016, 0.37723277, 0.37189441, 0.36648196, 0.36099209,
	0.35542120, 0.34976542, 0.34402054, 0.33818204, 0.33224495, 0.32620390, 0.32005298, 0.31378574,
	0.30739505, 0.30087304, 0.29421096, 0.28739907, 0.28042645, 0.27328078, 0.26594810, 0.25841250,
	0.25065566, 0.24265636, 0.23438976, 0.22582651, 0.21693146, 0.20766198, 0.19796546, 0.18777575,
	0.17700769, 0.16554844, 0.15324301, 0.13986823, 0.12508152, 0.10830610, 0.08841715, 0.06251018,
}

double acos(double x) {
	int index;

	if (x < -1)
		x = -1;
	if (x > 1)
		x = 1;
	index = (float) (1.0 + x) * 511.9;
	return acostable[index];
}

double atan2(double y, double x) {
	float base;
	float temp;
	float dir;
	float test;
	int i;

	if (x < 0) {
		if (y >= 0) {
			// quad 1
			base = M_PI / 2;
			temp = x;
			x = y;
			y = -temp;
		} else {
			// quad 2
			base = M_PI;
			x = -x;
			y = -y;
		}
	} else {
		if (y < 0) {
			// quad 3
			base = 3 * M_PI / 2;
			temp = x;
			x = -y;
			y = temp;
		}
	}

	if (y > x) {
		base += M_PI / 2;
		temp = x;
		x = y;
		y = temp;
		dir = -1;
	} else {
		dir = 1;
	}

	// calcualte angle in octant 0
	if (x == 0) {
		return base;
	}
	y /= x;

	for (i = 0; i < 512; i++) {
		test = sintable[i] / sintable[1023 - i];
		if (test > y) {
			break;
		}
	}

	return base + dir * i * (M_PI / 2048);
}


#endif

/*
===============
powN

Raise a double to a integer power
===============
 */
static double powN(double base, int exp) {
	if (exp >= 0) {
		double result = 1.0;

		// calculate x, x^2, x^4, ... by repeated squaring
		// and multiply together the ones corresponding to the
		// binary digits of the exponent
		// e.g. x^73 = x^(1 + 8 + 64) = x * x^8 * x^64
		while (exp > 0) {
			if (exp % 2 == 1)
				result *= base;

			base *= base;
			exp /= 2;
		}

		return result;
	}		// if exp is INT_MIN, the next clause will be upset,
		// because -exp isn't representable
	else if (exp == INT_MIN)
		return powN(base, exp + 1) / base;
		// x < 0
	else
		return 1.0 / powN(base, -exp);
}

double tan(double x) {
	return sin(x) / cos(x);
}


static int randSeed = 0;

void srand(unsigned seed) {
	randSeed = seed;
}

int rand(void) {
	randSeed = (69069 * randSeed + 1);
	return randSeed & 0x7fff;
}

double atof(const char *string) {
	float sign;
	float value;
	int c;


	// skip whitespace
	while (*string <= ' ') {
		if (!*string) {
			return 0;
		}
		string++;
	}

	// check sign
	switch (*string) {
		case '+':
			string++;
			sign = 1;
			break;
		case '-':
			string++;
			sign = -1;
			break;
		default:
			sign = 1;
			break;
	}

	// read digits
	value = 0;
	c = string[0];
	if (c != '.') {
		do {
			c = *string++;
			if (c < '0' || c > '9') {
				break;
			}
			c -= '0';
			value = value * 10 + c;
		} while (1);
	} else {
		string++;
	}

	// check for decimal point
	if (c == '.') {
		double fraction;

		fraction = 0.1;
		do {
			c = *string++;
			if (c < '0' || c > '9') {
				break;
			}
			c -= '0';
			value += c * fraction;
			fraction *= 0.1;
		} while (1);

	}

	// not handling 10e10 notation...

	return value * sign;
}

double _atof(const char **stringPtr) {
	const char *string;
	float sign;
	float value;
	int c = '0';

	string = *stringPtr;

	// skip whitespace
	while (*string <= ' ') {
		if (!*string) {
			*stringPtr = string;
			return 0;
		}
		string++;
	}

	// check sign
	switch (*string) {
		case '+':
			string++;
			sign = 1;
			break;
		case '-':
			string++;
			sign = -1;
			break;
		default:
			sign = 1;
			break;
	}

	// read digits
	value = 0;
	if (string[0] != '.') {
		do {
			c = *string++;
			if (c < '0' || c > '9') {
				break;
			}
			c -= '0';
			value = value * 10 + c;
		} while (1);
	}

	// check for decimal point
	if (c == '.') {
		double fraction;

		fraction = 0.1;
		do {
			c = *string++;
			if (c < '0' || c > '9') {
				break;
			}
			c -= '0';
			value += c * fraction;
			fraction *= 0.1;
		} while (1);

	}

	// not handling 10e10 notation...
	*stringPtr = string;

	return value * sign;
}

/*
==============
strtod

Without an errno variable, this is a fair bit less useful than it is in libc
but it's still a fair bit more capable than atof or _atof
Handles inf[inity], nan (ignoring case), hexadecimals, and decimals
Handles decimal exponents like 10e10 and hex exponents like 0x7f8p20
10e10 == 10000000000 (power of ten)
0x7f8p20 == 0x7f800000 (decimal power of two)
The variable pointed to by endptr will hold the location of the first character
in the nptr string that was not used in the conversion
==============
 */
double strtod(const char *nptr, const char **endptr) {
	double res;
	qboolean neg = qfalse;

	// skip whitespace
	while (isspace(*nptr))
		nptr++;

	// special string parsing
	if (Q_strequaln(nptr, "nan", 3)) {
		floatint_t nan;
		if (endptr == NULL) {
			nan.ui = 0x7fffffff;
			return nan.f;
		}
		*endptr = &nptr[3];
		// nan can be followed by a bracketed number (in hex, octal,
		// or decimal) which is then put in the mantissa
		// this can be used to generate signalling or quiet NaNs, for
		// example (though I doubt it'll ever be used)
		// note that nan(0) is infinity!
		if (nptr[3] == '(') {
			const char *end;
			int mantissa = strtol(&nptr[4], &end, 0);
			if (*end == ')') {
				nan.ui = 0x7f800000 | (mantissa & 0x7fffff);
				if (endptr)
					*endptr = &end[1];
				return nan.f;
			}
		}
		nan.ui = 0x7fffffff;
		return nan.f;
	}
	if (Q_strequaln(nptr, "inf", 3)) {
		floatint_t inf;
		inf.ui = 0x7f800000;
		if (endptr == NULL)
			return inf.f;
		if (Q_strequaln(&nptr[3], "inity", 5))
			*endptr = &nptr[8];
		else
			*endptr = &nptr[3];
		return inf.f;
	}

	// normal numeric parsing
	// sign
	if (*nptr == '-') {
		nptr++;
		neg = qtrue;
	} else if (*nptr == '+')
		nptr++;
	// hex
	if (Q_strequaln(nptr, "0x", 2)) {
		// track if we use any digits
		const char *s = &nptr[1], *end = s;
		nptr += 2;
		res = 0;
		while (qtrue) {
			if (isdigit(*nptr))
				res = 16 * res + (*nptr++ -'0');
			else if (*nptr >= 'A' && *nptr <= 'F')
				res = 16 * res + 10 + *nptr++ -'A';
			else if (*nptr >= 'a' && *nptr <= 'f')
				res = 16 * res + 10 + *nptr++ -'a';
			else
				break;
		}
		// if nptr moved, save it
		if (end + 1 < nptr)
			end = nptr;
		if (*nptr == '.') {
			float place;
			nptr++;
			// 1.0 / 16.0 == 0.0625
			// I don't expect the float accuracy to hold out for
			// very long but since we need to know the length of
			// the string anyway we keep on going regardless
			for (place = 0.0625;; place /= 16.0) {
				if (isdigit(*nptr))
					res += place * (*nptr++ -'0');
				else if (*nptr >= 'A' && *nptr <= 'F')
					res += place * (10 + *nptr++ -'A');
				else if (*nptr >= 'a' && *nptr <= 'f')
					res += place * (10 + *nptr++ -'a');
				else
					break;
			}
			if (end < nptr)
				end = nptr;
		}
		// parse an optional exponent, representing multiplication
		// by a power of two
		// exponents are only valid if we encountered at least one
		// digit already (and have therefore set end to something)
		if (end != s && tolower(*nptr) == 'p') {
			int exp;
			// apparently (confusingly) the exponent should be
			// decimal
			exp = strtol(&nptr[1], &end, 10);
			if (&nptr[1] == end) {
				// no exponent
				if (endptr)
					*endptr = nptr;
				return res;
			}

			res *= powN(2, exp);
		}
		if (endptr)
			*endptr = end;
		return res;
	}		// decimal
	else {
		// track if we find any digits
		const char *end = nptr, *p = nptr;
		// this is most of the work
		for (res = 0; isdigit(*nptr);
				res = 10 * res + *nptr++ -'0');
		// if nptr moved, we read something
		if (end < nptr)
			end = nptr;
		if (*nptr == '.') {
			// fractional part
			float place;
			nptr++;
			for (place = 0.1; isdigit(*nptr); place /= 10.0)
				res += (*nptr++ -'0') * place;
			// if nptr moved, we read something
			if (end + 1 < nptr)
				end = nptr;
		}
		// exponent
		// meaningless without having already read digits, so check
		// we've set end to something
		if (p != end && tolower(*nptr) == 'e') {
			int exp;
			exp = strtol(&nptr[1], &end, 10);
			if (&nptr[1] == end) {
				// no exponent
				if (endptr)
					*endptr = nptr;
				return res;
			}

			res *= powN(10, exp);
		}
		if (endptr)
			*endptr = end;
		return res;
	}
}

int atoi(const char *string) {
	int sign;
	int value;
	int c;


	// skip whitespace
	while (*string <= ' ') {
		if (!*string) {
			return 0;
		}
		string++;
	}

	// check sign
	switch (*string) {
		case '+':
			string++;
			sign = 1;
			break;
		case '-':
			string++;
			sign = -1;
			break;
		default:
			sign = 1;
			break;
	}

	// read digits
	value = 0;
	do {
		c = *string++;
		if (c < '0' || c > '9') {
			break;
		}
		c -= '0';
		value = value * 10 + c;
	} while (1);

	// not handling 10e10 notation...

	return value * sign;
}

int _atoi(const char **stringPtr) {
	int sign;
	int value;
	int c;
	const char *string;

	string = *stringPtr;

	// skip whitespace
	while (*string <= ' ') {
		if (!*string) {
			return 0;
		}
		string++;
	}

	// check sign
	switch (*string) {
		case '+':
			string++;
			sign = 1;
			break;
		case '-':
			string++;
			sign = -1;
			break;
		default:
			sign = 1;
			break;
	}

	// read digits
	value = 0;
	do {
		c = *string++;
		if (c < '0' || c > '9') {
			break;
		}
		c -= '0';
		value = value * 10 + c;
	} while (1);

	// not handling 10e10 notation...

	*stringPtr = string;

	return value * sign;
}

/*
==============
strtol

Handles any base from 2 to 36. If base is 0 then it guesses
decimal, hex, or octal based on the format of the number (leading 0 or 0x)
Will not overflow - returns LONG_MIN or LONG_MAX as appropriate
 *endptr is set to the location of the first character not used
==============
 */
long strtol(const char *nptr, const char **endptr, int base) {
	long res;
	qboolean pos = qtrue;

	if (endptr)
		*endptr = nptr;
	// bases other than 0, 2, 8, 16 are very rarely used, but they're
	// not much extra effort to support
	if (base < 0 || base == 1 || base > 36)
		return 0;
	// skip leading whitespace
	while (isspace(*nptr))
		nptr++;
	// sign
	if (*nptr == '-') {
		nptr++;
		pos = qfalse;
	} else if (*nptr == '+')
		nptr++;
	// look for base-identifying sequences e.g. 0x for hex, 0 for octal
	if (nptr[0] == '0') {
		nptr++;
		// 0 is always a valid digit
		if (endptr)
			*endptr = nptr;
		if (*nptr == 'x' || *nptr == 'X') {
			if (base != 0 && base != 16) {
				// can't be hex, reject x (accept 0)
				if (endptr)
					*endptr = nptr;
				return 0;
			}
			nptr++;
			base = 16;
		} else if (base == 0)
			base = 8;
	} else if (base == 0)
		base = 10;
	res = 0;
	while (qtrue) {
		int val;
		if (isdigit(*nptr))
			val = *nptr - '0';
		else if (islower(*nptr))
			val = 10 + *nptr - 'a';
		else if (isupper(*nptr))
			val = 10 + *nptr - 'A';
		else
			break;
		if (val >= base)
			break;
		// we go negative because LONG_MIN is further from 0 than
		// LONG_MAX
		if (res < (LONG_MIN + val) / base)
			res = LONG_MIN; // overflow
		else
			res = res * base - val;
		nptr++;
		if (endptr)
			*endptr = nptr;
	}
	if (pos) {
		// can't represent LONG_MIN positive
		if (res == LONG_MIN)
			res = LONG_MAX;
		else
			res = -res;
	}
	return res;
}

int abs(int n) {
	return n < 0 ? -n : n;
}

double fabs(double x) {
	return x < 0 ? -x : x;
}



//=========================================================

/* 
 * New implementation by Patrick Powell and others for vsnprintf.
 * Supports length checking in strings.
 */

/*
 * Copyright Patrick Powell 1995
 * This code is based on code written by Patrick Powell (papowell@astart.com)
 * It may be used for any purpose as long as this notice remains intact
 * on all source code distributions
 */

/**************************************************************
 * Original:
 * Patrick Powell Tue Apr 11 09:48:21 PDT 1995
 * A bombproof version of doprnt (dopr) included.
 * Sigh.  This sort of thing is always nasty do deal with.  Note that
 * the version here does not include floating point...
 *
 * snprintf() is used instead of sprintf() as it does limit checks
 * for string length.  This covers a nasty loophole.
 *
 * The other functions are there to prevent NULL pointers from
 * causing nast effects.
 *
 * More Recently:
 *  Brandon Long <blong@fiction.net> 9/15/96 for mutt 0.43
 *  This was ugly.  It is still ugly.  I opted out of floating point
 *  numbers, but the formatter understands just about everything
 *  from the normal C string format, at least as far as I can tell from
 *  the Solaris 2.5 printf(3S) man page.
 *
 *  Brandon Long <blong@fiction.net> 10/22/97 for mutt 0.87.1
 *    Ok, added some minimal floating point support, which means this
 *    probably requires libm on most operating systems.  Don't yet
 *    support the exponent (e,E) and sigfig (g,G).  Also, fmtint()
 *    was pretty badly broken, it just wasn't being exercised in ways
 *    which showed it, so that's been fixed.  Also, formated the code
 *    to mutt conventions, and removed dead code left over from the
 *    original.  Also, there is now a builtin-test, just compile with:
 *           gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm
 *    and run snprintf for results.
 * 
 *  Thomas Roessler <roessler@guug.de> 01/27/98 for mutt 0.89i
 *    The PGP code was using unsigned hexadecimal formats. 
 *    Unfortunately, unsigned formats simply didn't work.
 *
 *  Michael Elkins <me@cs.hmc.edu> 03/05/98 for mutt 0.90.8
 *    The original code assumed that both snprintf() and vsnprintf() were
 *    missing.  Some systems only have snprintf() but not vsnprintf(), so
 *    the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
 *
 *  Andrew Tridgell (tridge@samba.org) Oct 1998
 *    fixed handling of %.0f
 *    added test for HAVE_LONG_DOUBLE
 *
 *  Russ Allbery <rra@stanford.edu> 2000-08-26
 *    fixed return value to comply with C99
 *    fixed handling of snprintf(NULL, ...)
 *
 *  Hrvoje Niksic <hniksic@arsdigita.com> 2000-11-04
 *    include <config.h> instead of "config.h".
 *    moved TEST_SNPRINTF stuff out of HAVE_SNPRINTF ifdef.
 *    include <stdio.h> for NULL.
 *    added support and test cases for long long.
 *    don't declare argument types to (v)snprintf if stdarg is not used.
 *    use int instead of short int as 2nd arg to va_arg.
 *
 **************************************************************/

/* BDR 2002-01-13  %e and %g were being ignored.  Now do something,
   if not necessarily correctly */

#if (SIZEOF_LONG_DOUBLE > 0)
/* #ifdef HAVE_LONG_DOUBLE */
#define LDOUBLE long double
#else
#define LDOUBLE double
#endif

#if (SIZEOF_LONG_LONG > 0)
/* #ifdef HAVE_LONG_LONG */
#define LLONG long long
#else
#define LLONG long
#endif

static int dopr(char *buffer, size_t maxlen, const char *format,
		va_list args);
static int fmtstr(char *buffer, size_t *currlen, size_t maxlen,
		char *value, int flags, int min, int max);
static int fmtint(char *buffer, size_t *currlen, size_t maxlen,
		LLONG value, int base, int min, int max, int flags);
static int fmtfp(char *buffer, size_t *currlen, size_t maxlen,
		LDOUBLE fvalue, int min, int max, int flags);
static int dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c);

/*
 * dopr(): poor man's version of doprintf
 */

/* format read states */
#define DP_S_DEFAULT 0
#define DP_S_FLAGS   1
#define DP_S_MIN     2
#define DP_S_DOT     3
#define DP_S_MAX     4
#define DP_S_MOD     5
#define DP_S_MOD_L   6
#define DP_S_CONV    7
#define DP_S_DONE    8

/* format flags - Bits */
#define DP_F_MINUS  (1 << 0)
#define DP_F_PLUS   (1 << 1)
#define DP_F_SPACE  (1 << 2)
#define DP_F_NUM    (1 << 3)
#define DP_F_ZERO   (1 << 4)
#define DP_F_UP     (1 << 5)
#define DP_F_UNSIGNED  (1 << 6)

/* Conversion Flags */
#define DP_C_SHORT   1
#define DP_C_LONG    2
#define DP_C_LLONG   3
#define DP_C_LDOUBLE 4

#define char_to_int(p) (p - '0')
#define MAX(p,q) ((p >= q) ? p : q)
#define MIN(p,q) ((p <= q) ? p : q)

static int dopr(char *buffer, size_t maxlen, const char *format, va_list args) {
	char ch;
	LLONG value;
	LDOUBLE fvalue;
	char *strvalue;
	int min;
	int max;
	int state;
	int flags;
	int cflags;
	int total;
	size_t currlen;

	state = DP_S_DEFAULT;
	currlen = flags = cflags = min = 0;
	max = -1;
	ch = *format++;
	total = 0;

	while (state != DP_S_DONE) {
		if (ch == '\0')
			state = DP_S_DONE;

		switch (state) {
			case DP_S_DEFAULT:
				if (ch == '%')
					state = DP_S_FLAGS;
				else
					total += dopr_outch(buffer, &currlen, maxlen, ch);
				ch = *format++;
				break;
			case DP_S_FLAGS:
				switch (ch) {
					case '-':
						flags |= DP_F_MINUS;
						ch = *format++;
						break;
					case '+':
						flags |= DP_F_PLUS;
						ch = *format++;
						break;
					case ' ':
						flags |= DP_F_SPACE;
						ch = *format++;
						break;
					case '#':
						flags |= DP_F_NUM;
						ch = *format++;
						break;
					case '0':
						flags |= DP_F_ZERO;
						ch = *format++;
						break;
					default:
						state = DP_S_MIN;
						break;
				}
				break;
			case DP_S_MIN:
				if ('0' <= ch && ch <= '9') {
					min = 10 * min + char_to_int(ch);
					ch = *format++;
				}
				else if (ch == '*') {
					min = va_arg(args, int);
					ch = *format++;
					state = DP_S_DOT;
				}
				else
					state = DP_S_DOT;
				break;
			case DP_S_DOT:
				if (ch == '.') {
					state = DP_S_MAX;
					ch = *format++;
				}
				else
					state = DP_S_MOD;
				break;
			case DP_S_MAX:
				if ('0' <= ch && ch <= '9') {
					if (max < 0)
						max = 0;
					max = 10 * max + char_to_int(ch);
					ch = *format++;
				}
				else if (ch == '*') {
					max = va_arg(args, int);
					ch = *format++;
					state = DP_S_MOD;
				}
				else
					state = DP_S_MOD;
				break;
			case DP_S_MOD:
				switch (ch) {
					case 'h':
						cflags = DP_C_SHORT;
						ch = *format++;
						break;
					case 'l':
						cflags = DP_C_LONG;
						ch = *format++;
						break;
					case 'L':
						cflags = DP_C_LDOUBLE;
						ch = *format++;
						break;
					default:
						break;
				}
				if (cflags != DP_C_LONG)
					state = DP_S_CONV;
				else
					state = DP_S_MOD_L;
				break;
			case DP_S_MOD_L:
				switch (ch) {
					case 'l':
						cflags = DP_C_LLONG;
						ch = *format++;
						break;
					default:
						break;
				}
				state = DP_S_CONV;
				break;
			case DP_S_CONV:
				switch (ch) {
					case 'd':
					case 'i':
						if (cflags == DP_C_SHORT)
							value = (short int) va_arg(args, int);
						else if (cflags == DP_C_LONG)
							value = va_arg(args, long int);
						else if (cflags == DP_C_LLONG)
							value = va_arg(args, LLONG);
						else
							value = va_arg(args, int);
						total += fmtint(buffer, &currlen, maxlen, value, 10, min, max, flags);
						break;
					case 'o':
						flags |= DP_F_UNSIGNED;
						if (cflags == DP_C_SHORT)
							//	  value = (unsigned short int) va_arg (args, unsigned short int); // Thilo: This does not work because the rcc compiler cannot do that cast correctly.
							value = va_arg(args, unsigned int) & ((1 << sizeof (unsigned short int) * 8) - 1); // Using this workaround instead.
						else if (cflags == DP_C_LONG)
							value = va_arg(args, unsigned long int);
						else if (cflags == DP_C_LLONG)
							value = va_arg(args, unsigned LLONG);
						else
							value = va_arg(args, unsigned int);
						total += fmtint(buffer, &currlen, maxlen, value, 8, min, max, flags);
						break;
					case 'u':
						flags |= DP_F_UNSIGNED;
						if (cflags == DP_C_SHORT)
							value = va_arg(args, unsigned int) & ((1 << sizeof (unsigned short int) * 8) - 1);
						else if (cflags == DP_C_LONG)
							value = va_arg(args, unsigned long int);
						else if (cflags == DP_C_LLONG)
							value = va_arg(args, unsigned LLONG);
						else
							value = va_arg(args, unsigned int);
						total += fmtint(buffer, &currlen, maxlen, value, 10, min, max, flags);
						break;
					case 'X':
						flags |= DP_F_UP;
					case 'x':
						flags |= DP_F_UNSIGNED;
						if (cflags == DP_C_SHORT)
							value = va_arg(args, unsigned int) & ((1 << sizeof (unsigned short int) * 8) - 1);
						else if (cflags == DP_C_LONG)
							value = va_arg(args, unsigned long int);
						else if (cflags == DP_C_LLONG)
							value = va_arg(args, unsigned LLONG);
						else
							value = va_arg(args, unsigned int);
						total += fmtint(buffer, &currlen, maxlen, value, 16, min, max, flags);
						break;
					case 'f':
						if (cflags == DP_C_LDOUBLE)
							fvalue = va_arg(args, LDOUBLE);
						else
							fvalue = va_arg(args, double);
						/* um, floating point? */
						total += fmtfp(buffer, &currlen, maxlen, fvalue, min, max, flags);
						break;
					case 'E':
						flags |= DP_F_UP;
					case 'e':
						if (cflags == DP_C_LDOUBLE)
							fvalue = va_arg(args, LDOUBLE);
						else
							fvalue = va_arg(args, double);
						/* um, floating point? */
						total += fmtfp(buffer, &currlen, maxlen, fvalue, min, max, flags);
						break;
					case 'G':
						flags |= DP_F_UP;
					case 'g':
						if (cflags == DP_C_LDOUBLE)
							fvalue = va_arg(args, LDOUBLE);
						else
							fvalue = va_arg(args, double);
						/* um, floating point? */
						total += fmtfp(buffer, &currlen, maxlen, fvalue, min, max, flags);
						break;
					case 'c':
						total += dopr_outch(buffer, &currlen, maxlen, va_arg(args, int));
						break;
					case 's':
						strvalue = va_arg(args, char *);
						total += fmtstr(buffer, &currlen, maxlen, strvalue, flags, min, max);
						break;
					case 'p':
						strvalue = va_arg(args, void *);
						total += fmtint(buffer, &currlen, maxlen, (long) strvalue, 16, min,
								max, flags);
						break;
					case 'n':
						if (cflags == DP_C_SHORT) {
							short int *num;
							num = va_arg(args, short int *);
							*num = currlen;
						} else if (cflags == DP_C_LONG) {
							long int *num;
							num = va_arg(args, long int *);
							*num = currlen;
						}
						else if (cflags == DP_C_LLONG) {
							LLONG *num;
							num = va_arg(args, LLONG *);
							*num = currlen;
						}
						else {
							int *num;
							num = va_arg(args, int *);
							*num = currlen;
						}
						break;
					case '%':
						total += dopr_outch(buffer, &currlen, maxlen, ch);
						break;
					case 'w':
						/* not supported yet, treat as next char */
						ch = *format++;
						break;
					default:
						/* Unknown, skip */
						break;
				}
				ch = *format++;
				state = DP_S_DEFAULT;
				flags = cflags = min = 0;
				max = -1;
				break;
			case DP_S_DONE:
				break;
			default:
				/* hmm? */
				break; /* some picky compilers need this */
		}
	}
	if (buffer != NULL) {
		if (currlen < maxlen - 1)
			buffer[currlen] = '\0';
		else
			buffer[maxlen - 1] = '\0';
	}
	return total;
}

static int fmtstr(char *buffer, size_t *currlen, size_t maxlen,
		char *value, int flags, int min, int max) {
	int padlen, strln; /* amount to pad */
	int cnt = 0;
	int total = 0;

	if (value == 0) {
		value = "<NULL>";
	}

	for (strln = 0; value[strln]; ++strln); /* strlen */
	if (max >= 0 && max < strln)
		strln = max;
	padlen = min - strln;
	if (padlen < 0)
		padlen = 0;
	if (flags & DP_F_MINUS)
		padlen = -padlen; /* Left Justify */

	while (padlen > 0) {
		total += dopr_outch(buffer, currlen, maxlen, ' ');
		--padlen;
	}
	while (*value && ((max < 0) || (cnt < max))) {
		total += dopr_outch(buffer, currlen, maxlen, *value++);
		++cnt;
	}
	while (padlen < 0) {
		total += dopr_outch(buffer, currlen, maxlen, ' ');
		++padlen;
	}
	return total;
}

/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */

static int fmtint(char *buffer, size_t *currlen, size_t maxlen,
		LLONG value, int base, int min, int max, int flags) {
	int signvalue = 0;
	unsigned LLONG uvalue;
	char convert[24];
	int place = 0;
	int spadlen = 0; /* amount to space pad */
	int zpadlen = 0; /* amount to zero pad */
	const char *digits;
	int total = 0;

	if (max < 0)
		max = 0;

	uvalue = value;

	if (!(flags & DP_F_UNSIGNED)) {
		if (value < 0) {
			signvalue = '-';
			uvalue = -value;
		} else
			if (flags & DP_F_PLUS) /* Do a sign (+/i) */
			signvalue = '+';
		else
			if (flags & DP_F_SPACE)
			signvalue = ' ';
	}

	if (flags & DP_F_UP)
		/* Should characters be upper case? */
		digits = "0123456789ABCDEF";
	else
		digits = "0123456789abcdef";

	do {
		convert[place++] = digits[uvalue % (unsigned) base];
		uvalue = (uvalue / (unsigned) base);
	} while (uvalue && (place < sizeof (convert)));
	if (place == sizeof (convert)) place--;
	convert[place] = 0;

	zpadlen = max - place;
	spadlen = min - MAX(max, place) - (signvalue ? 1 : 0);
	if (zpadlen < 0) zpadlen = 0;
	if (spadlen < 0) spadlen = 0;
	if (flags & DP_F_ZERO) {
		zpadlen = MAX(zpadlen, spadlen);
		spadlen = 0;
	}
	if (flags & DP_F_MINUS)
		spadlen = -spadlen; /* Left Justifty */

#ifdef DEBUG_SNPRINTF
	dprint(1, (debugfile, "zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
			zpadlen, spadlen, min, max, place));
#endif

	/* Spaces */
	while (spadlen > 0) {
		total += dopr_outch(buffer, currlen, maxlen, ' ');
		--spadlen;
	}

	/* Sign */
	if (signvalue)
		total += dopr_outch(buffer, currlen, maxlen, signvalue);

	/* Zeros */
	if (zpadlen > 0) {
		while (zpadlen > 0) {
			total += dopr_outch(buffer, currlen, maxlen, '0');
			--zpadlen;
		}
	}

	/* Digits */
	while (place > 0)
		total += dopr_outch(buffer, currlen, maxlen, convert[--place]);

	/* Left Justified spaces */
	while (spadlen < 0) {
		total += dopr_outch(buffer, currlen, maxlen, ' ');
		++spadlen;
	}

	return total;
}

static LDOUBLE abs_val(LDOUBLE value) {
	LDOUBLE result = value;

	if (value < 0)
		result = -value;

	return result;
}

static long round(LDOUBLE value) {
	long intpart;

	intpart = value;
	value = value - intpart;
	if (value >= 0.5)
		intpart++;

	return intpart;
}

static int fmtfp(char *buffer, size_t *currlen, size_t maxlen,
		LDOUBLE fvalue, int min, int max, int flags) {
	int signvalue = 0;
	LDOUBLE ufvalue;
	char iconvert[20];
	char fconvert[20];
	int iplace = 0;
	int fplace = 0;
	int padlen = 0; /* amount to pad */
	int zpadlen = 0;
	int caps = 0;
	int total = 0;
	long intpart;
	long fracpart;

	/* 
	 * AIX manpage says the default is 0, but Solaris says the default
	 * is 6, and sprintf on AIX defaults to 6
	 */
	if (max < 0)
		max = 6;

	ufvalue = abs_val(fvalue);

	if (fvalue < 0)
		signvalue = '-';
	else
		if (flags & DP_F_PLUS) /* Do a sign (+/i) */
		signvalue = '+';
	else
		if (flags & DP_F_SPACE)
		signvalue = ' ';

#if 0
	if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
#endif

	intpart = ufvalue;

	/* 
	 * Sorry, we only support 9 digits past the decimal because of our 
	 * conversion method
	 */
	if (max > 9)
		max = 9;

	/* We "cheat" by converting the fractional part to integer by
	 * multiplying by a factor of 10
	 */
	fracpart = round((powN(10, max)) * (ufvalue - intpart));

	if (fracpart >= powN(10, max)) {
		intpart++;
		fracpart -= powN(10, max);
	}

#ifdef DEBUG_SNPRINTF
	dprint(1, (debugfile, "fmtfp: %f =? %d.%d\n", fvalue, intpart, fracpart));
#endif

	/* Convert integer part */
	do {
		iconvert[iplace++] =
				(caps ? "0123456789ABCDEF" : "0123456789abcdef")[intpart % 10];
		intpart = (intpart / 10);
	} while (intpart && (iplace < 20));
	if (iplace == 20) iplace--;
	iconvert[iplace] = 0;

	/* Convert fractional part */
	do {
		fconvert[fplace++] =
				(caps ? "0123456789ABCDEF" : "0123456789abcdef")[fracpart % 10];
		fracpart = (fracpart / 10);
	} while (fracpart && (fplace < 20));
	if (fplace == 20) fplace--;
	fconvert[fplace] = 0;

	/* -1 for decimal point, another -1 if we are printing a sign */
	padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
	zpadlen = max - fplace;
	if (zpadlen < 0)
		zpadlen = 0;
	if (padlen < 0)
		padlen = 0;
	if (flags & DP_F_MINUS)
		padlen = -padlen; /* Left Justifty */

	if ((flags & DP_F_ZERO) && (padlen > 0)) {
		if (signvalue) {
			total += dopr_outch(buffer, currlen, maxlen, signvalue);
			--padlen;
			signvalue = 0;
		}
		while (padlen > 0) {
			total += dopr_outch(buffer, currlen, maxlen, '0');
			--padlen;
		}
	}
	while (padlen > 0) {
		total += dopr_outch(buffer, currlen, maxlen, ' ');
		--padlen;
	}
	if (signvalue)
		total += dopr_outch(buffer, currlen, maxlen, signvalue);

	while (iplace > 0)
		total += dopr_outch(buffer, currlen, maxlen, iconvert[--iplace]);

	/*
	 * Decimal point.  This should probably use locale to find the correct
	 * char to print out.
	 */
	if (max > 0) {
		total += dopr_outch(buffer, currlen, maxlen, '.');

		while (zpadlen-- > 0)
			total += dopr_outch(buffer, currlen, maxlen, '0');

		while (fplace > 0)
			total += dopr_outch(buffer, currlen, maxlen, fconvert[--fplace]);
	}

	while (padlen < 0) {
		total += dopr_outch(buffer, currlen, maxlen, ' ');
		++padlen;
	}

	return total;
}

static int dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c) {
	if (*currlen + 1 < maxlen)
		buffer[(*currlen)++] = c;
	return 1;
}

int Q_vsnprintf(char *str, size_t length, const char *fmt, va_list args) {
	if (str != NULL)
		str[0] = 0;
	return dopr(str, length, fmt, args);
}

int Q_snprintf(char *str, size_t length, const char *fmt, ...) {
	va_list ap;
	int retval;

	va_start(ap, fmt);
	retval = Q_vsnprintf(str, length, fmt, ap);
	va_end(ap);

	return retval;
}

/* this is really crappy */
int sscanf(const char *buffer, const char *fmt, ...) {
	int cmd;
	va_list ap;
	int count;
	size_t len;

	va_start(ap, fmt);
	count = 0;

	while (*fmt) {
		if (fmt[0] != '%') {
			fmt++;
			continue;
		}

		fmt++;
		cmd = *fmt;

		if (isdigit(cmd)) {
			len = (size_t) _atoi(&fmt);
			cmd = *(fmt - 1);
		} else {
			len = MAX_STRING_CHARS - 1;
			fmt++;
		}

		switch (cmd) {
			case 'i':
			case 'd':
			case 'u':
				*(va_arg(ap, int *)) = _atoi(&buffer);
				break;
			case 'f':
				*(va_arg(ap, float *)) = _atof(&buffer);
				break;
			case 's':
			{
				char *s = va_arg(ap, char *);
				while (isspace(*buffer))
					buffer++;
				while (*buffer && !isspace(*buffer) && len-- > 0)
					*s++ = *buffer++;
				*s++ = '\0';
				break;
			}
		}
	}

	va_end(ap);
	return count;
}

#endif
